package com.jy.rhin.config.ws;

import com.jy.rhin.facade.ws.basic.notification.NotificationConsumer;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: ws客户端工厂
 * @Author: lww
 * @Date: 2022/5/18
 */
@Slf4j
@Component
public class WsClientFactory extends BaseWsFactory implements ApplicationListener<ApplicationStartedEvent> {
    @Resource
    WsClientProperties wsClientProperties;
    /**
     * 缓存所有ws客户端代理类
     */
    Map<Class<?>, Object> factoryBeanMap = new HashMap<>();

    /**
     * 获取指定类型的ws客户端代理，可以通过该代理调用ws接口
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getClient(Class<T> clazz) {
        if (!factoryBeanMap.containsKey(clazz)) {
            throw new RuntimeException(String.format("未配置WS客户端 %s 类", clazz.getName()));
        }
        Object client = factoryBeanMap.get(clazz);
        return clazz.cast(client);
    }

    /**
     * 获取通知接口的ws客户端，不同的订阅者接口地址不同，需要根据地址实时创建client对象
     * @param address
     * @return
     */
    public NotificationConsumer getNotificationClient(String address){
        return createClient(NotificationConsumer.class, address);
    }

    /**
     * 监听服务启动完成事件，启动完成后，缓存ws客户端代理
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        List<WsClientProperties.WsApiProperties> serverList = wsClientProperties.getServerList();
        if (serverList != null) {
            serverList.forEach(this::add);
        }
    }

    /**
     * 添加一个ws客户端，通过  {@link JaxWsProxyFactoryBean#create(Class) }创建客户端代理，并缓存到 {@link WsClientFactory#factoryBeanMap} 中
     *
     * @param properties
     */
    private void add(WsClientProperties.WsApiProperties properties) {
        Class<?> wsClass = properties.getWsClass();
        Object client = createClient(wsClass, properties.getWsUrl());
        factoryBeanMap.put(wsClass, client);
    }

    /**
     * 创建webService客户端
     * @param clazz
     * @param address
     * @return
     * @param <T>
     */
    private <T> T createClient(Class<T> clazz, String address){
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(clazz);
        factory.setAddress(address);
        try {
            URI uri = new URI(address);
            factory.getInInterceptors().addAll(matchInterceptor(wsClientProperties.getInInterceptors(), uri.getPath()));
            factory.getOutInterceptors().addAll(matchInterceptor(wsClientProperties.getOutInterceptors(), uri.getPath()));
        } catch (URISyntaxException e) {
            log.error("初始化ws Client [{}] 异常, 无法解析wsUrl: {}", clazz, address);
            throw new RuntimeException(e);
        }
        return factory.create(clazz);
    }

}
